#include "NetworkConnect.hpp"
#include <stdexcept>
#include <msgpack.hpp>
#include <typeinfo>
#include <fmt/format.h>

//模板生成请求代码
void NetworkConnect::GetHttpRequire(const std::string& path,std::function<void(httplib::Result&)> func)
{
  //检查是否能连接成功
  httplib::Result res=client.Get(path);
  if(res!=nullptr)
    func(res);
  else
  {
    auto err=res.error();
    throw std::runtime_error(httplib::to_string(err));
  }
}

template<class T>
T NetworkConnect::DecodeMsgPackOneData(const std::string& val)
{
  msgpack::object_handle result;
  msgpack::unpack(result,val.data(),val.size());
  T res=result->as<T>();
  return res;
}

template<class T>
T NetworkConnect::autoRequireAndDecode(const std::string& path)
{
  if constexpr(std::is_same_v<T,void>)
  {
    GetHttpRequire(path,[this](httplib::Result& res){
      if(res->status!=200)
        throw std::runtime_error("Http请求失败");
    });
  }
  else{
    T val;
    GetHttpRequire(path,[this,&val](httplib::Result& res){
      if(res->status==200)
        val=DecodeMsgPackOneData<T>(res->body);
      else
        throw std::runtime_error("Http请求失败");
    });
    return val;
  }
}


NetworkConnect::NetworkConnect(std::string url)
  : client(url)
{
  GetHttpRequire("/hello",[this](httplib::Result& res){
    if(res->status!=200)
      throw std::runtime_error("服务器错误");
  });
}

NetworkConnect::~NetworkConnect()
{
}

long NetworkConnect::CreateTask(std::string name)
{
  return autoRequireAndDecode<long>(fmt::format("/createTask?name={}",name));
}

bool NetworkConnect::CheckStuExist(long id)
{
  return autoRequireAndDecode<bool>(fmt::format("/CheckStuExist?id={}",id));
}

std::string NetworkConnect::GetStudentInf(long id)
{
  return autoRequireAndDecode<std::string>(fmt::format("/getStuInf?id={}",id));
}

void NetworkConnect::StartShot(long task_id,long stu_id)
{
  autoRequireAndDecode<void>(fmt::format("/startShot?taskid={}&stuid={}",task_id,stu_id));
}

void NetworkConnect::StopShot()
{
  autoRequireAndDecode<void>("/stopShot");
}

bool NetworkConnect::CheckShotStatus()
{
  return autoRequireAndDecode<bool>("/CheckShotStatus");
}
